package com.youlu.campus.service.wechat;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.DES;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.youlu.campus.base.common.AccessTokenResult;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.common.utils.HttpClientUtil;
import com.youlu.campus.common.utils.IdGeneratorUtils;
import com.youlu.campus.common.utils.Md5Utils;
import com.youlu.campus.entity.ActivityInfo;
import com.youlu.campus.entity.ActivityTaskInfo;
import com.youlu.campus.entity.UserPO;
import com.youlu.campus.entity.VO.res.WechatCodeResponse;
import com.youlu.campus.entity.WechatACode;
import com.youlu.campus.entity.enums.TaskBizType;
import com.youlu.campus.service.activity.ActivityService;
import com.youlu.campus.service.activity.ActivityTaskService;
import com.youlu.campus.service.douyin.DouYinShareCodeService;
import com.youlu.campus.service.file.FileService;
import com.youlu.campus.service.utils.CryptoDEUtil;
import com.youlu.campus.service.utils.HttpClientUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class WXacodeService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Value("${spring.profiles.active}")
    private String env;



    @Value("${sys.pay.wx.mini.appId}")
    private String appId;
    @Value("${sys.pay.wx.mini.secret}")
    private String secret;
    @Value("${sys.pay.wx.mini.pagePath}")
    private String pagePath;

    private final static String  ACCESS_TOKEN_URL = "https://api.weixin.qq" +
            ".com/cgi-bin/token?grant_type=client_credential" +
            "&appid=%s&secret=%s";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private FileService fileService;

    @Autowired
    private ActivityTaskService activityTaskService;

    @Autowired
    private ActivityService activityService;

    private final static String ACCESS_TOKEN_KEY ="campus:access:token:appId:%s";

    private final static String WX_CODE_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s";

    @Autowired
    private DouYinShareCodeService douYinShareCodeService;

    public static void main(String[] args) throws Exception {
        String text = "{sharedByOpenId=o53NI5S_C-PjL6tCTp4qEnnOvUvc,taskId=62d6194260d5e83f652a39d1&activityId" +
                "=62d6194260d5e83f652a39d0,sharedByUserId=6080f8c760d5e8542ebb94e0}";
        //随机生成密钥
        DES des = new DES(Mode.CTS, Padding.PKCS5Padding, "0CoJUm6Qyw8W8jud".getBytes(), "01020304".getBytes());
        System.out.println(Md5Utils.encrypt32(text).length());
        byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DESede.getValue(),
                CryptoDEUtil.SERCRET_KEY.getBytes("utf-8")).getEncoded();
        //构建
        SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.DESede,key);
        //加密
        byte[] encrypt = aes.encrypt(text,"utf-8");
        System.out.println(new String(encrypt));
        //解密
        byte[] decrypt = aes.decrypt(encrypt);
        System.out.println("解密"+new String(decrypt, "UTF-8"));
        //加密为16进制表示
        String encryptHex = aes.encryptHex(text);
        System.out.println("16进制"+encryptHex.length());
        //解密为字符串
        String decryptStr = aes.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8);
        System.out.println("解密为字符串"+decryptStr);

    }

    public WechatACode findById(String id){
        return this.mongoTemplate.findById(id,WechatACode.class);
    }


    public String getShareCode(UserPO currentUser,String activityId){
        String currentPlatform = currentUser.getCurrentPlatform();
        switch (currentPlatform){
            case "wechat-mini":
                return getShareWxaCode(currentUser,activityId);
            case "douyin-mini":
                return douYinShareCodeService.getShareWxaCode(currentUser,activityId);
        }
        return "";
    }

    public String getShareWxaCode(UserPO currentUser,String activityId){
        log.info("【获取小程序码】WXacodeService.getShareWxaCode userId ->{}|activityId->{}",currentUser.getId(),activityId);
        ActivityTaskInfo activityTaskInfo = activityTaskService.find(activityId, TaskBizType.INVITE);
        Query query = new Query();
        query.addCriteria(Criteria.where("userId").is(currentUser.getId()));
        query.addCriteria(Criteria.where("activityId").is(activityId));
        WechatACode wechatACode = this.mongoTemplate.findOne(query, WechatACode.class);
        if(Objects.nonNull(wechatACode)){
            return wechatACode.getWxaCode();
        }
        ActivityInfo activityInfo = activityService.findOne(activityId);
        String accessToken = getAccessToken();
        String  wxCodeUrl =  String.format(WX_CODE_URL, accessToken);
        Date now = new Date();
        Update update = new Update();
        update.set("sharedByOpenId",currentUser.getOpenId());
        update.set("taskId",activityTaskInfo.getId());
        update.set("activityType",activityInfo.getType());
        update.set("platform",currentUser.getCurrentPlatform());
        update.setOnInsert("createdTime",now);
        update.set("updatedTime",now);
        FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
        findAndModifyOptions.returnNew(Boolean.TRUE);
        findAndModifyOptions.upsert(Boolean.TRUE);
        WechatACode wxaCode = this.mongoTemplate.findAndModify(query, update, findAndModifyOptions, WechatACode.class);
        Map<String, Object> paramMap = new HashMap<>(10);
        paramMap.put("scene",wxaCode.getId());
        paramMap.put("width", 430);
        paramMap.put("auto_color", false);
        if("test".equals(env)){
            paramMap.put("env_version", "trial");
        }else if ("beta".equals(env)){
            paramMap.put("env_version", "trial");
        }else{
            paramMap.put("env_version", "release");
        }
        Map<String, String> color = new HashMap<>(3);
        color.put("r", "0");
        color.put("g", "0");
        color.put("b", "0");
        paramMap.put("line_color", color);
        paramMap.put("is_hyaline", Boolean.TRUE);
        paramMap.put("page", pagePath);
        InputStream inputStream = null;
        String imageUrl ="";
        try {
            HttpResponse resp = HttpClientUtils.postJsonDataMethod(wxCodeUrl, paramMap);
            long length = resp.getEntity().getContentLength();
            log.info("小程序码文件长度为:{}", length);
            if (length <= 1000) {
                deleteAccessToken();
                String content = HttpClientUtils.getContent(resp);
                if (content == null) {
                    log.error("【获取小程序码】WXacodeService.getShareWxaCode 生成小程序码异常,解析信息为空");
                    throw new BusinessException("生成小程序码错误，请重试!");
                }
                WechatCodeResponse codeResponse = JSON.parseObject(content, WechatCodeResponse.class);
                if (codeResponse != null && StringUtils.isNotBlank(codeResponse.getErrcode())) {
                    log.error("【获取小程序码】WXacodeService.getShareWxaCode 生成小程序码异常，错误码:{},错误信息:{}",
                            codeResponse.getErrcode(), codeResponse.getErrmsg());
                    throw new BusinessException("生成小程序码错误，请重试!");
                }
            }
            inputStream = resp.getEntity().getContent();
            log.info("【获取小程序码】WXacodeService.getShareWxaCode 上传到七牛云");
            String fileName = "wxacode" + IdGeneratorUtils.generateId() + ".png";
            imageUrl=  fileService.uploadFile(inputStream, fileName);
            JSONObject jsonObject = HttpClientUtils.getContentNoClose(inputStream);
            if (jsonObject != null && jsonObject.getString("errcode") != null) {
                String errmsg = jsonObject.getString("errmsg");
                log.error("获取小程序二维码错误：{}", errmsg);
                throw new BusinessException(errmsg);
            }
            wxaCode.setWxaCode(imageUrl);
            this.mongoTemplate.save(wxaCode);
        } catch (Exception e) {
            log.error("【获取小程序码】WXacodeService.getShareWxaCode 获取小程序码接口异常:{}", e.getMessage());
            throw new BusinessException("获取小程序码接口异常");
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        log.info("【获取小程序码】WXacodeService.getShareWxaCode 生成微信小程序码完成,地址:{}", imageUrl);
        return imageUrl;
    }

    private void deleteAccessToken() {
        String accessTokenKey = String.format(ACCESS_TOKEN_KEY, appId);
        stringRedisTemplate.delete(accessTokenKey);
    }

    public String getAccessToken(){
        String accessTokenKey = String.format(ACCESS_TOKEN_KEY, appId);
        String accessTokenValue = this.stringRedisTemplate.opsForValue().get(accessTokenKey);
        if(StringUtils.isNotBlank(accessTokenValue)){
            return accessTokenValue;
        }
        String accessTokenUrl = String.format(ACCESS_TOKEN_URL,this.appId,secret);
        log.info("WXacodeService.getAccessToken url ->{}",accessTokenUrl);
        try {
            String result = HttpClientUtil.get(accessTokenUrl, null, null, 3000, "utf8", 3, true);
            log.info("获取【accessToken】appId ->{} return result -> {}", appId, result);
            if(StringUtils.isBlank(result)){
                throw new  BusinessException("获取AccessToken返回信息为空");
            }
            AccessTokenResult tokenResult = JSON.parseObject(result, AccessTokenResult.class);
            if (tokenResult.getErrcode() != 0) {
                log.info("获取AccessToken错误,错误信息:{}", tokenResult.getErrmsg());
                throw new BusinessException(tokenResult.getErrmsg());
            }
            this.stringRedisTemplate.opsForValue().set(accessTokenKey,tokenResult.getAccessToken(),
                    tokenResult.getExpiresIn()-5, TimeUnit.SECONDS);
            return tokenResult.getAccessToken();
        } catch (IOException e) {
            e.printStackTrace();
            throw new  BusinessException("获取AccessToken返回信息为空");
        } catch (URISyntaxException e) {
            e.printStackTrace();
            throw new  BusinessException("获取AccessToken返回信息为空");
        }catch (Exception e) {
            e.printStackTrace();
            throw new  BusinessException(e.getMessage());
        }


    }


}
